using System;
using System.Collections.Generic;
using System.Text;
using HTML;

namespace PointBridge.SPDX
{
    public class OptionsSet
    {
        #region Constructors
        public OptionsSet() { }
        public OptionsSet(OptionsSet obj)
        {
            CopyFrom(obj);
        }
        public OptionsSet(LAHTMLParser parser)
        {
            ParseXML(parser);
        }
        #endregion

        #region Sort Methods
        public void SortAlphabetically()
        {
            IComparer<OptionLine> myComparer = new OptionLineCompareAlphabetically();
            _arr.Sort(myComparer);
        }
        public void SortByOrder()
        {
            IComparer<OptionLine> myComparer = new OptionLineCompareByOrder();
            _arr.Sort(myComparer);
        }
        private class OptionLineCompareAlphabetically : IComparer<OptionLine>
        {
            int IComparer<OptionLine>.Compare(OptionLine x, OptionLine y)
            {
                int result = x.optionName.CompareTo(y.optionName);
                if (result == 0) result = x.order.CompareTo(y.order);
                return result;
            }
        }
        private class OptionLineCompareByOrder : IComparer<OptionLine>
        {
            int IComparer<OptionLine>.Compare(OptionLine x, OptionLine y)
            {
                int result = x.order.CompareTo(y.order);
                if (result == 0) result = x.optionName.CompareTo(y.optionName);
                return result;
            }
        }
        #endregion

        #region Methods
        public int FindIndexByOptionName(string optionName)
        {
            int result = _arr.FindIndex(delegate(OptionLine optionLine) { return (optionLine.optionName == optionName); });
            if (result == -1) throw new PointBridgeEx("FindIndex returned -1. Criteria: " + optionName);
            return result;
        }
        public OptionLine FindByOptionNameNullsAllowed(string optionName)
        {
            OptionLine result = _arr.Find(delegate(OptionLine optionLine) { return (optionLine.optionName == optionName); });
            return result;
        }
        public OptionLine FindByOptionName(string optionName)
        {
            OptionLine result = FindByOptionNameNullsAllowed(optionName);
            if (result == null) throw new PointBridgeEx("Find returned null. Criteria: " + optionName);
            return result;
        }
        public void CopyFrom(OptionsSet obj)
        {
            Clear();
            for (int i = 0; i < obj.count; i++)
            {
                Add(new OptionLine(obj[i]));
            }
        }
        public void SetValuesFromAnotherSet(OptionsSet anotherSet)
        {
            for (int i = 0; i < anotherSet.count; i++)
            {
                OptionLine line = FindByOptionNameNullsAllowed(anotherSet[i].optionName);
                if (line != null) line.optionValue = anotherSet[i].optionValue;
            }
        }
        public void SetValuesNotPresentInAnotherSetToTrue(OptionsSet anotherSet)
        {
            for (int i = 0; i < count; i++)
            {
                OptionLine line = anotherSet.FindByOptionNameNullsAllowed(this[i].optionName);
                if (line == null) this[i].optionValue = true;
            }
        }

        public void SelectAll()
        {
            for (int i = 0; i < count; i++)
            {
                this[i].optionValue = true;
            }
        }
        public void SelectNone()
        {
            for (int i = 0; i < count; i++)
            {
                this[i].optionValue = false;
            }
        }
        public void Add(OptionLine optionLine)
        {
            _arr.Add(optionLine);
        }
        public void ValidateOneOptionSetEx()
        {
            if (ValidateOneOptionSetNoEx() == false) throw new NoOptionsSetEx();
        }
        public bool ValidateOneOptionSetNoEx()
        {
            for (int i = 0; i < count; i++)
            {
                if (this[i].optionValue == true) return true;
            }
            return false;
        }

        public void Clear()
        {
            _arr.Clear();
        }
        public int count
        {
            get { return _arr.Count; }
        }
        public OptionLine this[int key]
        {
            get { return _arr[key]; }
            set { _arr[key] = value; }
        }
        public bool GetOptionValue(string OptionName)
        {
            return FindByOptionName(OptionName).optionValue;
        }
        #endregion

        #region XML Methods
        public void ParseXML(LAHTMLParser parser)
        {
            AttributeList tag = parser.ProcessTag("OptionsSet");
            ReadAttributeList(tag);
            _arr.Clear();
            if (tag["/"] != null) return; //if this tag is also closing tag return
            while (true)
            {
                tag = parser.PeekNextTag();
                if (tag.Name == "/OptionsSet") break;
                Add(new OptionLine(parser));
            }
            parser.ProcessTag("/OptionsSet");
        }
        public string ToXMLString()
        {
            StringBuilder xml = new StringBuilder();
            AttributeList tag = ToAttributeList();
            xml.Append(tag.ToXMLString(false));
            for (int i = 0; i < count; i++)
            {
                xml.Append(this[i].ToXMLString());
            }
            xml.Append(tag.ToClosingXMLString());
            return xml.ToString();
        }
        private void ReadAttributeList(AttributeList tag)
        {
            if (tag.Name != "OptionsSet") throw new PointBridgeEx("Trying to read FilterOptionsSet from where tag = " + tag.Name);
            int ver;
            tag.ReadXMLAttribute("_ver", out ver);
            if (ver > _ver) throw new PointBridgeEx("Trying to read OptionsSet version=" + ver + " while class version=" + _ver);
        }
        private AttributeList ToAttributeList()
        {
            AttributeList tag = new AttributeList();
            tag.Name = "OptionsSet";
            tag.AddXMLAttribute("_ver", _ver);
            return tag;
        }
        #endregion

        #region Accessors and Mutatots
        #endregion

        #region Internal fields
        private const int _ver = 1;
        protected List<OptionLine> _arr = new List<OptionLine>();
        //protected List<OptionGroup> _optionGroups = null;
        #endregion
    }
}
